/**
XML与TJS2变量之间的相互转换

支持void，整数，实数，字符串，时间(转换为毫秒数)，数组和字典

双向转换，遇到数组和字典则递归处理

在此感谢 Lee Thomason 提供了 简便易用的 tinyxml 库

*/

//---------------------------------------------------------------------------
#include <windows.h>
#include <tinyxml.h>
#include "tp_stub.h"
#include <string>

//---------------------------------------------------------------------------



std::wstring utf8to16(const std::string& src)
{
    std::wstring temp;
    const char* putf8 = src.c_str();
    char utf8;
    uint32_t utf32, utf32head;
    int movelength;

    while(*putf8 != '\0')
    {
        utf8 = *putf8;
        if(utf8 & 0x80)
        {
            utf32 = 0;
            movelength = 0;
            while(utf8 & 0x40)
            {
                utf32 = (utf32 << 6) + ((*(++putf8)) & 0x3F);
                movelength += 5;
                utf8 <<= 1;
            }

            utf32head = (unsigned char)(utf8 << 1);
            utf32head <<= (movelength - 1);

            utf32 += utf32head;

            temp.push_back(utf32);

            putf8++;
        }
        else
        {
            temp.push_back(utf8);
            putf8++;
        }
    }
    return temp;
}

std::string utf16to8(const std::wstring& src)
{
    std::string temp;
    uint32_t utf32, utf32mask = 0xFFFFFFFF;
    char utf8temp[5], utf8mask = 0xFF;
    int utf8length;

    for(int i=0; i<src.length(); i++)
    {
        utf32 = src[i];
        if(utf32 & 0xFFFFFF80)
        {
            utf8length = 1;

            while(utf32 & 0xFFFFFFC0)
            {
                utf8temp[utf8length - 1] = (static_cast<char>(utf32 & 0x3F)) | 0x80;
                utf32 >>= 6;
                if(utf32 & (utf32mask << (6 - utf8length)))
                {
                    utf8length++;
                }
                else
                {
                    break;
                }
            }

            temp.push_back((utf8mask << (7 - utf8length)) | static_cast<char>(utf32));

            for(int t=utf8length-1; t>=0; t--)
            {
                temp.push_back(utf8temp[t]);
            }
        }
        else
        {
            temp.push_back(static_cast<char>(utf32));
        }
    }

    return temp;
}

std::wstring ansitoutf16(const std::string& src)
{
    //预转换，得到所需空间的大小
    int wcsLen = ::MultiByteToWideChar(CP_ACP, NULL, src.c_str(), src.length(), NULL, 0);

    wchar_t* wszString = new wchar_t[wcsLen + 1];

    //转换
    ::MultiByteToWideChar(CP_ACP, NULL, src.c_str(), src.length(), wszString, wcsLen);

    //最后加上'\0'
    wszString[wcsLen] = '\0';

    std::wstring utf16temp(wszString);

    delete[] wszString;
    wszString =NULL;

    return utf16temp;
}

std::string utf16toansi(const std::wstring& src)
{
    //预转换，得到所需空间的大小，这次用的函数和上面名字相反
    int ansiLen = ::WideCharToMultiByte(CP_ACP, NULL, src.c_str(), src.length(), NULL, 0, NULL, NULL);

    char* szAnsi = new char[ansiLen + 1];

    //转换
    ::WideCharToMultiByte(CP_ACP, NULL, src.c_str(), src.length(), szAnsi, ansiLen, NULL, NULL);

    //最后加上'\0'
    szAnsi[ansiLen] = '\0';

    std::string ansitemp(szAnsi);

    delete[] szAnsi;
    szAnsi =NULL;

    return ansitemp;
}

std::string ansitoutf8(const std::string& src)
{
    return utf16to8(ansitoutf16(src));
}

std::string utf8toansi(const std::string& src)
{
    return utf16toansi(utf8to16(src));
}

TiXmlElement tjsVar2Xml(tTJSVariant& src)
{
    TiXmlElement xmlelm("VAR");

    switch (src.Type())
    {
        case tvtVoid:
            xmlelm.SetAttribute("type", "tvtVoid");
            xmlelm.InsertEndChild(TiXmlText("void"));
            break;
        case tvtObject:
            iTJSDispatch2* obj = src.AsObject();

            if(obj == NULL) // 是null
            {
                xmlelm.SetAttribute("type", "null");
                xmlelm.InsertEndChild(TiXmlText("null"));
                break;
            }
            else if(obj->IsInstanceOf(TJS_MEMBERMUSTEXIST, NULL, NULL, L"Array", NULL) == TJS_S_TRUE) //是数组
            {
                xmlelm.SetAttribute("type", "Array");

                // 获取数组中的元素数量
                tTJSVariant countvar;
                obj->PropGet(TJS_MEMBERMUSTEXIST, L"count", NULL, &countvar, obj);
                tjs_int count = countvar.AsInteger();
                xmlelm.SetAttribute("count", (int)count);

                // 循环获取数组中的各个元素
                tTJSVariant tempvar;
                for(tjs_int i=0; i<count; i++)
                {
                    obj->PropGetByNum(0, i, &tempvar, obj);
                    xmlelm.InsertEndChild(tjsVar2Xml(tempvar)); // 递归
                }
            }
            else if(obj->IsInstanceOf(TJS_MEMBERMUSTEXIST, NULL, NULL, L"Dictionary", NULL) == TJS_S_TRUE) // 是字典
            {
                xmlelm.SetAttribute("type", "Dictionary");

                tTJSVariant* param[1];
                param[0] = &src;
                iTJSDispatch2* arrayobj = TJSCreateArrayObject();
                arrayobj->FuncCall(TJS_MEMBERMUSTEXIST, L"assign", NULL, NULL, 1, param, arrayobj);

                // 获取数组中的元素数量
                tTJSVariant countvar;
                arrayobj->PropGet(TJS_MEMBERMUSTEXIST, L"count", NULL, &countvar, arrayobj);
                tjs_int count = countvar.AsInteger();

                // 循环获取数组中的各个元素 每次两个值前面的是字典的key后面的是字典的value
                tTJSVariant tempvar;
                std::string keytmp;
                for(tjs_int i=0; i<count; i+=2)
                {
                    arrayobj->PropGetByNum(0, i, &tempvar, arrayobj);
                    keytmp = utf16to8(((tTJSString)tempvar).c_str());

                    arrayobj->PropGetByNum(0, i + 1, &tempvar, arrayobj);
                    ((TiXmlElement*)xmlelm.InsertEndChild(tjsVar2Xml(tempvar)/*递归*/))->SetAttribute("key", keytmp);
                }

                arrayobj->Release();
            }
            else if(obj->IsInstanceOf(TJS_MEMBERMUSTEXIST, NULL, NULL, L"Date", NULL) == TJS_S_TRUE) // 是时间
            {
                xmlelm.SetAttribute("type", "Date");

                tTJSVariant timevar;
                obj->FuncCall(TJS_MEMBERMUSTEXIST, L"getTime", NULL, &timevar, 0, NULL, obj);

                xmlelm.InsertEndChild(TiXmlText(utf16to8(((tTJSString)timevar).c_str())));
            }
            else
            {
                xmlelm.SetAttribute("type", "tvtObject");
                xmlelm.InsertEndChild(TiXmlText(utf16to8(((tTJSString)src).c_str())));
            }
            obj->Release();
            break;
        case tvtString:
            xmlelm.SetAttribute("type", "tvtString");
            xmlelm.InsertEndChild(TiXmlText(utf16to8(((tTJSString)src).c_str())));
            break;
        case tvtInteger:
            xmlelm.SetAttribute("type", "tvtInteger");
            xmlelm.InsertEndChild(TiXmlText(utf16to8(((tTJSString)src).c_str())));
            break;
        case tvtReal:
            xmlelm.SetAttribute("type", "tvtReal");
            xmlelm.InsertEndChild(TiXmlText(utf16to8(((tTJSString)src).c_str())));
            break;
        default:
            break;
    }

    return xmlelm;
}

std::wstring tjsVar2XmlUtf16(tTJSVariant& src)
{
    TiXmlDocument xmldoc;

    xmldoc.InsertEndChild(tjsVar2Xml(src));

    std::string xmlstr;

    xmlstr << xmldoc;

    return utf8to16(xmlstr);

/*
    std::wstring tempstr(L"");

    switch (src.Type())
    {
        case tvtVoid:
            tempstr += L"<VAR type=\"tvtVoid\">void</VAR>";
            break;
        case tvtObject:
            iTJSDispatch2* obj = src.AsObject();
            if(obj->IsInstanceOf(TJS_MEMBERMUSTEXIST, NULL, NULL, L"Array", NULL) == TJS_S_TRUE) //是数组
            {
                tempstr += L"<VAR type=\"Array\" count=\"";

                // 获取数组中的元素数量
                tTJSVariant countvar;
                obj->PropGet(TJS_MEMBERMUSTEXIST, L"count", NULL, &countvar, obj);
                tjs_int count = countvar.AsInteger();
                tempstr += ((tTJSString)countvar).c_str();
                tempstr += L"\">";

                // 循环获取数组中的各个元素
                tTJSVariant tempvar;
                for(tjs_int i=0; i<count; i++)
                {
                    obj->PropGetByNum(0, i, &tempvar, obj);
                    tempstr += tjsVar2XmlUtf16(tempvar); // 递归
                }

                tempstr += L"</VAR>";
            }
            else if(obj->IsInstanceOf(TJS_MEMBERMUSTEXIST, NULL, NULL, L"Dictionary", NULL) == TJS_S_TRUE) // 是字典
            {
                tempstr += L"<VAR type=\"Dictionary\">";

                // 创建一个数组
                tTJSVariant arrayvar;
                TVPExecuteExpression(TJS_W("[]"), &arrayvar);

                tTJSVariant* param[1];
                param[0] = &src;
                iTJSDispatch2* arrayobj = arrayvar.AsObject();
                arrayobj->FuncCall(TJS_MEMBERMUSTEXIST, L"assign", NULL, &arrayvar, 1, param, arrayobj);

                // 获取数组中的元素数量
                tTJSVariant countvar;
                arrayobj->PropGet(TJS_MEMBERMUSTEXIST, L"count", NULL, &countvar, arrayobj);
                tjs_int count = countvar.AsInteger();

                // 循环获取数组中的各个元素 每次两个值前面的是字典的key后面的是字典的value
                tTJSVariant tempvar;
                for(tjs_int i=0; i<count; i+=2)
                {
                    arrayobj->PropGetByNum(0, i, &tempvar, arrayobj);
                    tempstr = tempstr + L"<DICPAIR key=\"" + ((tTJSString)tempvar).c_str() + L"\">";

                    arrayobj->PropGetByNum(0, i + 1, &tempvar, arrayobj);
                    tempstr += tjsVar2XmlUtf16(tempvar); // 递归

                    tempstr += L"</DICPAIR>";
                }

                arrayobj->Release();

                tempstr += L"</VAR>";
            }
            else if(obj->IsInstanceOf(TJS_MEMBERMUSTEXIST, NULL, NULL, L"Date", NULL) == TJS_S_TRUE) // 是时间
            {

                tempstr += L"<VAR type=\"Date\">";

                tTJSVariant timevar;
                obj->FuncCall(TJS_MEMBERMUSTEXIST, L"getTime", NULL, &timevar, 0, NULL, obj);
                tempstr += ((tTJSString)timevar).c_str();

                tempstr += L"</VAR>";
            }
            else
                tempstr = tempstr + L"<VAR type=\"tvtObject\">" + ((tTJSString)src).c_str() + L"</VAR>";
            obj->Release();
            break;
        case tvtString:
            tempstr = tempstr + L"<VAR type=\"tvtString\">" + ((tTJSString)src).c_str() + L"</VAR>";
            break;
        case tvtInteger:
            tempstr = tempstr + L"<VAR type=\"tvtInteger\">" + ((tTJSString)src).c_str() + L"</VAR>";
            break;
        case tvtReal:
            tempstr = tempstr + L"<VAR type=\"tvtReal\">" + ((tTJSString)src).c_str() + L"</VAR>";
            break;
        default:
            break;
    }

    return tempstr;
*/
}

void xml2TjsVar(const TiXmlElement& src, tTJSVariant& out)
{
    std::string type = src.Attribute("type");

    if(type == "tvtVoid")
    {
        out = tTJSVariant();
    }
    else if(type == "tvtString")
    {
        out = (tTJSString)tTJSVariant(utf8to16(src.GetText()).c_str());
    }
    else if(type == "tvtInteger")
    {
        out = (tTVInteger)tTJSVariant(utf8to16(src.GetText()).c_str());
    }
    else if(type == "tvtReal")
    {
        out = (tTVReal)tTJSVariant(utf8to16(src.GetText()).c_str());
    }
    else if(type == "null")
    {
        tTJSVariant nullvar;
        TVPExecuteExpression(TJS_W("null"), &nullvar);
        out = nullvar;
    }
    else if(type == "Date")
    {
        tTJSVariant datevar;
        TVPExecuteExpression(TJS_W("new Date()"), &datevar);

        tTJSVariant timelong = (tTVInteger)(tTJSVariant(utf8to16(src.GetText()).c_str()));
        tTJSVariant* param[1];
        param[0] = &timelong;
        iTJSDispatch2* dateobj = datevar.AsObject();
        dateobj->FuncCall(TJS_MEMBERMUSTEXIST, L"setTime", NULL, NULL, 1, param, dateobj);

        out = datevar;

        dateobj->Release();
    }
    else if(type == "Array")
    {
        tjs_int count = 0;
        iTJSDispatch2* arrayobj = TJSCreateArrayObject();
        tTJSVariant tempvar;
        const TiXmlElement* pelm = src.FirstChildElement();
        while(pelm != NULL)
        {
            xml2TjsVar(*pelm, tempvar); // 递归
            arrayobj->PropSetByNum(0, count++, &tempvar, arrayobj);

            pelm = pelm->NextSiblingElement();
        }

        out = tTJSVariant(arrayobj);

        arrayobj->Release();
    }
    else if(type == "Dictionary")
    {
        iTJSDispatch2* dicobj = TJSCreateDictionaryObject();
        tTJSVariant tempvar;
        const TiXmlElement* pelm = src.FirstChildElement();
        while(pelm != NULL)
        {
            xml2TjsVar(*pelm, tempvar); // 递归
            dicobj->PropSet(TJS_MEMBERENSURE, utf8to16(pelm->Attribute("key")).c_str(), NULL, &tempvar, dicobj);

            pelm = pelm->NextSiblingElement();
        }

        out = tTJSVariant(dicobj);

        dicobj->Release();
    }
}

tTJSVariant xmlUtf162TjsVar(const std::wstring& src)
{
    TiXmlDocument xmldoc;

    xmldoc.Parse(utf16to8(src).c_str());

    const TiXmlElement* root = xmldoc.RootElement();

    tTJSVariant tempvar;

    xml2TjsVar(*root, tempvar);

    return tempvar;
}

tTJSString loadTextFile(const tTJSString& filename)
{
    tTJSString loadFileScript = TJS_W("[].load('");
    loadFileScript += filename;
    loadFileScript += TJS_W("')");

    // 利用Array读取文本数据
    tTJSVariant arrayvar;
    TVPExecuteExpression(loadFileScript, &arrayvar);

    // 获取数组中的元素数量
    iTJSDispatch2* arrayobj = arrayvar.AsObject();
    tTJSVariant countvar;
    arrayobj->PropGet(TJS_MEMBERMUSTEXIST, L"count", NULL, &countvar, arrayobj);
    tjs_int count = countvar.AsInteger();

    // 循环获取数组中的各个元素，然后连接在一起
    tTJSString textData(TJS_W(""));
    tTJSVariant tempvar;
    for(tjs_int i=0; i<count; i++)
    {
        arrayobj->PropGetByNum(0, i, &tempvar, arrayobj);
        textData += (tTJSString)tempvar; // 递归
    }

    return textData;
}

//---------------------------------------------------------------------------
// tjs变量(包括数组和字典)转换为XML字符串 只有一个参数，就是要转换的tjs变量 返回字符串数据
//---------------------------------------------------------------------------
class tTJSVar2XmlFunction : public tTJSDispatch
{
	tjs_error TJS_INTF_METHOD FuncCall(
		tjs_uint32 flag, const tjs_char * membername, tjs_uint32 *hint,
		tTJSVariant *result,
		tjs_int numparams, tTJSVariant **param, iTJSDispatch2 *objthis);
} * TJSVar2XmlFunction;

tjs_error TJS_INTF_METHOD tTJSVar2XmlFunction::FuncCall(
	tjs_uint32 flag, const tjs_char * membername, tjs_uint32 *hint,
	tTJSVariant *result,
	tjs_int numparams, tTJSVariant **param, iTJSDispatch2 *objthis)
{
	if(numparams != 1) return TJS_E_BADPARAMCOUNT;

    tTJSString resultstr(tjsVar2XmlUtf16(*param[0]).c_str());

	if(result)
	{
		*result = resultstr;
	}

	return TJS_S_OK;
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// XML字符串转换为tjs变量(包括数组和字典) 只有一个参数，就是要转换的XML字符串或者文件名，需要带扩展名 返回tjs变量
//---------------------------------------------------------------------------
class tXml2TJSVarFunction : public tTJSDispatch
{
	// 例として、与えられた引数の合計を求める関数
	// (引数の中に実数があれば答えも実数、そうでなければ答えは整数にする)

	tjs_error TJS_INTF_METHOD FuncCall(
		tjs_uint32 flag, const tjs_char * membername, tjs_uint32 *hint,
		tTJSVariant *result,
		tjs_int numparams, tTJSVariant **param, iTJSDispatch2 *objthis);
} * Xml2TJSVarFunction;

tjs_error TJS_INTF_METHOD tXml2TJSVarFunction::FuncCall(
	tjs_uint32 flag, const tjs_char * membername, tjs_uint32 *hint,
	tTJSVariant *result,
	tjs_int numparams, tTJSVariant **param, iTJSDispatch2 *objthis)
{
	if(numparams != 1) return TJS_E_BADPARAMCOUNT;

	tTJSString src = (tTJSString)*param[0];

	if(src[0] != '<') // 按文件名处理
	{
        src = loadTextFile(src);
    }

    tTJSVariant resultvar = xmlUtf162TjsVar(src.c_str());

	if(result)
	{
		*result = resultvar;
	}

	return TJS_S_OK;
}
//---------------------------------------------------------------------------





//---------------------------------------------------------------------------
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason,
	void* lpReserved)
{
	return 1;
}
//---------------------------------------------------------------------------
static tjs_int GlobalRefCountAtInit = 0;
extern "C" HRESULT _stdcall _export V2Link(iTVPFunctionExporter *exporter)
{
	// スタブの初期化(必ず記述する)
	TVPInitImportStub(exporter);

	// AverageFunction の作成と登録
	tTJSVariant val;

	// TJS のグローバルオブジェクトを取得する
	iTJSDispatch2 * global = TVPGetScriptDispatch();



	//-----------------------------------------------------------------------
	// 1 まずオブジェクトを作成
	TJSVar2XmlFunction = new tTJSVar2XmlFunction();

	// 2 AverageFunction を tTJSVariant 型に変換
	val = tTJSVariant(TJSVar2XmlFunction);

	// 3 すでに val が AverageFunction を保持しているので、AverageFunction は
	//   Release する
	TJSVar2XmlFunction->Release();


	// 4 global の PropSet メソッドを用い、オブジェクトを登録する
	global->PropSet(
		TJS_MEMBERENSURE, // メンバがなかった場合には作成するようにするフラグ
		TJS_W("tjsvartoxml"), // メンバ名 ( かならず TJS_W( ) で囲む )
		NULL, // ヒント ( 本来はメンバ名のハッシュ値だが、NULL でもよい )
		&val, // 登録する値
		global // コンテキスト ( global でよい )
		);
	//-----------------------------------------------------------------------


	//-----------------------------------------------------------------------
	// 1 まずオブジェクトを作成
	Xml2TJSVarFunction = new tXml2TJSVarFunction();

	// 2 SumFunction を tTJSVariant 型に変換
	val = tTJSVariant(Xml2TJSVarFunction);

	// 3 すでに val が SumFunction を保持しているので、SumFunction は
	//   Release する
	Xml2TJSVarFunction->Release();


	// 4 global の PropSet メソッドを用い、オブジェクトを登録する
	global->PropSet(
		TJS_MEMBERENSURE, // メンバがなかった場合には作成するようにするフラグ
		TJS_W("xmltotjsvar"), // メンバ名 ( かならず TJS_W( ) で囲む )
		NULL, // ヒント ( 本来はメンバ名のハッシュ値だが、NULL でもよい )
		&val, // 登録する値
		global // コンテキスト ( global でよい )
		);
	//-----------------------------------------------------------------------

	// - global を Release する
	global->Release();

	// もし、登録する関数が複数ある場合は 1 ～ 4 を繰り返す


	// val をクリアする。
	// これは必ず行う。そうしないと val が保持しているオブジェクト
	// が Release されず、次に使う TVPPluginGlobalRefCount が正確にならない。
	val.Clear();


	// この時点での TVPPluginGlobalRefCount の値を
	GlobalRefCountAtInit = TVPPluginGlobalRefCount;
	// として控えておく。TVPPluginGlobalRefCount はこのプラグイン内で
	// 管理されている tTJSDispatch 派生オブジェクトの参照カウンタの総計で、
	// 解放時にはこれと同じか、これよりも少なくなってないとならない。
	// そうなってなければ、どこか別のところで関数などが参照されていて、
	// プラグインは解放できないと言うことになる。

	return S_OK;
}
//---------------------------------------------------------------------------
extern "C" HRESULT _stdcall _export V2Unlink()
{
	// 吉里吉里側から、プラグインを解放しようとするときに呼ばれる関数。

	// もし何らかの条件でプラグインを解放できない場合は
	// この時点で E_FAIL を返すようにする。
	// ここでは、TVPPluginGlobalRefCount が GlobalRefCountAtInit よりも
	// 大きくなっていれば失敗ということにする。
	if(TVPPluginGlobalRefCount > GlobalRefCountAtInit) return E_FAIL;
		// E_FAIL が帰ると、Plugins.unlink メソッドは偽を返す

	// TJS のグローバルオブジェクトに登録した average 関数などを削除する

	// - まず、TJS のグローバルオブジェクトを取得する
	iTJSDispatch2 * global = TVPGetScriptDispatch();

	// - global の DeleteMember メソッドを用い、オブジェクトを削除する
	if(global)
	{
		// TJS 自体が既に解放されていたときなどは
		// global は NULL になり得るので global が NULL でない
		// ことをチェックする

		global->DeleteMember(
			0, // フラグ ( 0 でよい )
			TJS_W("tjsvartoxml"), // メンバ名
			NULL, // ヒント
			global // コンテキスト
			);
		global->DeleteMember(
			0, // フラグ ( 0 でよい )
			TJS_W("xmltotjsvar"), // メンバ名
			NULL, // ヒント
			global // コンテキスト
			);
			// 登録した関数が複数ある場合は これを繰り返す
	}

	// - global を Release する
	if(global) global->Release();

	// スタブの使用終了(必ず記述する)
	TVPUninitImportStub();

	return S_OK;
}
//---------------------------------------------------------------------------
static tjs_char option_message[] =
L"テストカテゴリ:テスト設定項目1;これはテスト用のオプション設定項目です。|"
L"testoption1|select,*default;デフォルトの値,1;選択可能な値1,2;選択可能な値2\n"
L"テストカテゴリ:テスト設定項目2;これはテスト用のオプション設定項目です。|"
L"testoption2|string(64),*デフォルトの文字列\n";
//---------------------------------------------------------------------------
extern "C" const wchar_t* _stdcall _export GetOptionDesc()
{
	// GetOptionDesc は、吉里吉里設定ツールに渡すオプションの情報を返すための
	// 関数。
	// 一行につき一つのオプションに関する情報を書く。
	// 書式は
	// カテゴリ:設定名;説明|オプション名|オプションとして設定可能な値
	// (区切り記号に注意)
	// 「オプション名」には '-' (ハイフン) はつけない。
	// 「オプションとして設定可能な値」は以下の書式である。
	// タイプ,値の値;簡単な説明[,値;値の簡単な説明 ...]
	// 「タイプ」は現バージョンでは select と string のみ使用可能。

	// 「タイプ」に select を指定すると、コンボボックスから値を選択することが
	// できるようになる。
	// 「値;値の簡単な説明」の先頭に * をつけるとそれがデフォルトのオプション
	// であることを示す。デフォルトのオプションは必ず一つは無くてはならない。
	// 「値」は実際に吉里吉里本体へのオプションとして渡されるものを、
	// 「値の簡単な説明」は人間が読んで理解できるものを書く。

	// 「タイプ」に string を指定すると、エディットボックスでユーザが任意の文
	// 字列を入力できるようになる。
	// 「タイプ」に string を指定する場合は、string(n),*デフォルト文字列 の
	// 形で n には最大文字数を記述する。0 で文字数制限はなくなるが、できれば
	// 制限をつけたほうがよい。
	// 「デフォルト文字列」にはデフォルトの文字列を記述する。string(n) のあと
	// の , (カンマ) も * (アステリスク) も省略できない。

	// 例は /msg/win32/option_desc_ja.txt にもある。


	return option_message;

	// 各オプション末や、最後の改行記号を忘れると大変なことになる。


	// 吉里吉里設定などは、そのプラグインに設定可能な項目があるかどうかを
	// プラグインDLLの
	// 先頭2KB以内に "(--has-option--)" という文字列があるかどうか
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// (２重引用符は含めず)
	// で判断するため、先頭2KB以内にこれを書かなければならない。
	// bcc の場合はリンカオプション /GC で /GC"(--has-option--)"
	// と記述し、VC++ の場合もリンカオプション /COMMENT で
	// /COMMENT:"(--has-option--)" と記述する。
	// BCB の IDE からは プロジェクトオプションの「リンカ(詳細)」の
	// 「イメージのコメント」に "(--has-option--)" と書く。
	// (２重引用符で囲まないとエラーになるかもしれない)

	// UPX などで圧縮するとここの部分が消されてしまうので、
	// ヘッダの未使用領域 (0x80～0x1ff の 00 で埋まっている所など) に
	// 無理矢理書くなどする。

	// 本体に渡されたオプションは TVPGetCommandLine 関数で取得できる。
	// tTJSVariant val;
	// if(TVPGetCommandLine(TJS_W("-testoption1"), &val))
	// {
	//      // ここに オプション "-testoption1" が渡されていたときの
	//      // 処理を書く。val にはその値が入っている。
	//      // /environ/win32/wuvorbis/WuVorbisMainUnit.cpp 等参照
	// }
	// TVPGetcommandLine の実行は現バージョンでは高価なのでできれば
	// この関数の呼び出しの結果はキャッシュした方がよい。

	// 吉里吉里設定は、プラグインを「吉里吉里本体と同じフォルダ」と
	// 「吉里吉里本体のと同じフォルダにある plugin というフォルダ」から
	// しか検索しない。従って設定可能なオプションを含むプラグインは
	// Releaser などでアーカイブ中に含めてはならない(もともとReleaserで
	// プラグインを中に含めることは推奨されていない)。

	// この GetOptionDesc 関数内では tp_stub に記述されているような
	// 各吉里吉里本体内の関数は利用できない。
}
//---------------------------------------------------------------------------
/*
	V2Link と V2Unlink は DLL からエクスポートされている必要がある。
	従って、.def ファイルを作成し

EXPORTS
	V2Link
	V2Unlink

	と記述してプロジェクトに追加する。

	GetOptionsDesc を使う場合はそれも追加する。
*/
//---------------------------------------------------------------------------

